開發一個系統最無聊的過程大概就是除錯了,尤其是那種嘗試對 null 物件取值的錯誤(Object reference not set to an instance of an object.),這應該是大部分人剛踏入程式領域最常碰到的問題,為了從枯燥的除錯過程解脫,這篇就來介紹單元測試。
Blazor 的單元測試跟一般 C# 程式不太一樣,主要是檢查 Component 的畫面呈現邏輯、預期產生的 HTML 標籤跟實際畫面有無差異,畢竟 Blazor 是以後端語言撰寫而渲染的前端框架,如果要驗證資料有無錯誤,就是一般 C# 的單元測試了。
目前微軟的測試框架有 MSTest、NUnit 跟 xUnit 三種,但都不包含 Blazor,還好有社群愛好者建立了 bUnit 專案方便測試,不過 bUnit 並非框架而是專案,所以必須先建立三種測試框架之一的專案再去 NuGet 下載 bUnit。
首先在方案底下建立測試專案 BlazorServerMsTest,這邊筆者用 MSTest 框架,建立好後在專案名稱點兩下開啟csproj
檔,會看到 Sdk 為 "Microsoft.NET.Sdk"
,要改成 "Microsoft.NET.Sdk.Razor"
,否則 Blazor 編譯器不會渲染 Razor Component,TargetFramework
則要改成netcoreapp5.0
,這樣才能跟我們的 BlazorServer 專案相容。
接著去 NuGet 下載 bunit,並且參考主專案 BlazorServer,如果要測試的 Component 沒有用到資料,這樣就完成前置作業了,但現實狀況都是需要跟資料互動,也就是需要 Service,所以要下載可以產生假資料的 Service,筆者用的是 NSubstitute。
(註:如果想把測試方法都寫在 razor
檔案的 @code 區塊,就需要 _Import.razor
放置用到的 namespace,但因為筆者都用 code behind 的方式就不放了。)
單元測試中分為三個部分,Arrange、Act、Assert,Arrange 是指測試前的準備,Act 是找出要測試的項目,Assert 則是測試的結果。
我們來測試第一個 div.card
的 HTML 結果,先開啟網頁去複製第一個有 card class,這邊的 User Id 會隨資料改變。
下圖的19 行創建了 bUnit 這個測試實體並賦值給 ctx,20 行則利用 NSubstitute 建立的假的 IUserRepository,21 到 23 行呼叫了 GetUsersAsync()
不過丟了一個假的 List(),裡面只有一組 CustomUserViewModel
,這邊故意給錯誤的資料,24 行利用 DI 註冊 IUserRepository
服務。
27行利用 bUnit 渲染出 UserManagement
並賦值給 cut (component under test),但如果要比較整個 UserManagement
要貼上很多 HTML 標籤,所以再用 Find()
找出第一個有 card
class 的標籤,Find()
用的是 CSS 選擇器,代表可以放入標籤、class 或是 id 等等。
31行之後就是用找出來的 element
比較我們放進 MarkupMatches()
的 HTML 標籤,筆者這邊用的是多行,如果不想佔據版面的人也可以全部濃縮成一行,bUnit 不會比較斷行。
接著就是要實際測試了,可以按 ctrl + r, a
或是從上方的測試頁籤找到 Test Explorer,然後就能看到測試失敗,會告訴你實際的 HTML 跟預期的 HTML 差在哪裡,因為我們給的假資料跟預期的不同,所以出錯了。
我們把假資料的 UserId
跟 UsreName
改成跟預期的 HTML 資料一樣,按下 ctrl r, t
,就能看到通過測試了。
Ref:Creating a new bUnit test project
Ref: Writing tests for Blazor components